using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.IO;
using NSsh.Common.Packets;
using NSsh.Common.Types;
using NSsh.Common.Utility;
using NSsh.Server.ChannelLayer;
using NSsh.Server.TransportLayer;
using NSsh.Server.TransportLayer.State;

namespace NSsh.Client
{
    public class ClientAuthenticatedState : AbstractTransportState
    {
        Dictionary<uint, IChannel> _channels = new Dictionary<uint, IChannel>();
        private bool _channelOpenResponseReceived;
        private bool _channelTerminalResponseReceived;
        private string m_echoTestString = "hello world (" + Guid.NewGuid() + ")\r\n"; 

        private uint _serverChannelID;

        public override void Process(ITransportLayerManager manager)
        {
            manager.WritePacket(new IgnorePacket());

            IChannelProducer channel = CreateChannel(manager);
            ChannelOpenPacket channelOpenReq = new ChannelOpenPacket();
            //channelOpenReq.SenderChannel = channel.ChannelId;
            channelOpenReq.ChannelType = ChannelType.Session;
            manager.WritePacket(channelOpenReq);

            while (!_channelOpenResponseReceived) {
                ProcessPacket(manager);
            }

            manager.WritePacket(new IgnorePacket());

            ChannelRequestPacket channelReq = new ChannelRequestPacket();
            channelReq.RequestType = NSsh.Common.Packets.Channel.ChannelRequestType.Shell;
            channelReq.RecipientChannel = _serverChannelID;
            manager.WritePacket(channelReq);

            //while (!_channelTerminalResponseReceived) {
             //   ProcessPacket(manager);
            //}

            manager.WritePacket(new IgnorePacket());

            ChannelDataPacket dummyData = new ChannelDataPacket();
            dummyData.Data = Encoding.ASCII.GetBytes(m_echoTestString);
            manager.WritePacket(dummyData);

            while (true) {
                ProcessPacket(manager);
            }
        }

        private IChannelProducer CreateChannel(ITransportLayerManager manager) {
            
            IChannelProducer clientChannel = Dependency.Resolve<IChannelProducer>();
            ((ClientChannel)clientChannel).TransportLayerManager = manager;
            //channel.TransportLayerManager = manager;
            //channel.ChannelId = 1;
            //channel.SetChannelType(ChannelType.Session);
            //channel.Initialise();

            return clientChannel;
        }

        public void ChannelOpenFailurePacket(ITransportLayerManager manager, ChannelOpenFailurePacket packet) {
            throw new ApplicationException("Channel open request failed due to server rejection.");
        }

        public void ChannelOpenConfirmationPacket(ITransportLayerManager manager, ChannelOpenConfirmationPacket packet) {
            _serverChannelID = packet.SenderChannel;
            Console.WriteLine("Channel open channelid=" + packet.SenderChannel + ".");
            _channelOpenResponseReceived = true;
        }

        public override void ChannelDataPacket(ITransportLayerManager manager, ChannelDataPacket packet)
        {
            //IChannel channel = _channels[packet.RecipientChannel];
            //channel.ProcessChannelData(packet);
            string data = Encoding.ASCII.GetString(packet.Data);
            Console.WriteLine(data);

            if (data == m_echoTestString) {
                Console.WriteLine("Echo test was successfull.");
            }
            else {
                Console.WriteLine("Echo test failed.");
            }

            //manager.Disconnect(DisconnectReason.Unknown);
            //_channels[packet.RecipientChannel].Dispose();
        }

        public override void ChannelExtendedDataPacket(ITransportLayerManager manager, ChannelExtendedDataPacket packet)
        {
            IChannel channel = _channels[packet.RecipientChannel];
            channel.ProcessChannelExtendedData(packet);
        }

        public override void ChannelWindowAdjustPacket(ITransportLayerManager manager, ChannelWindowAdjustPacket packet)
        {
            //IChannel channel = _channels[packet.RecipientChannel];
            //channel.AdjustTransmitWindow(packet);
        }

        public override void ChannelEofPacket(ITransportLayerManager manager, ChannelEofPacket packet)
        {
            IChannel channel = _channels[packet.RecipientChannel];
            channel.EofReceived(packet);
        }

        public override void ChannelClosePacket(ITransportLayerManager manager, ChannelClosePacket packet)
        {
            IChannel channel = _channels[packet.RecipientChannel];
            channel.CloseReceived(packet);
            _channels.Remove(packet.RecipientChannel);
        }

        public override void ChannelRequestPacket(ITransportLayerManager manager, ChannelRequestPacket packet)
        {
            IChannel channel = _channels[packet.RecipientChannel];
            channel.RequestReceived(packet);
        }

        public override void DisconnectPacket(ITransportLayerManager manager, DisconnectPacket packet)
        {
            // Clean up each channel
            foreach (IChannel channel in _channels.Values)
            {
                channel.Dispose();
            }
            _channels.Clear();

            base.DisconnectPacket(manager, packet);
        }

        public override void Dispose(bool disposing)
        {
            if (disposing)
            {
                foreach (IChannel channel in _channels.Values)
                {
                    channel.Dispose();
                }
            }

            base.Dispose(disposing);
        }
    }
}
